package org.campuscontent.ui;

//import DefaultTreeTransferHandler;

import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.DnDConstants;
import java.io.DataInputStream;
import java.util.Enumeration;

import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.campuscontent.config.Config;
import org.campuscontent.io.Base64;
import org.campuscontent.io.PHPQuery;
import org.campuscontent.main.MainFrame;
import org.campuscontent.model.Exercise;
import org.campuscontent.model.Problem;
import org.campuscontent.util.DefaultTreeTransferHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class ExerciseTree extends JTree  
{
	public MainFrame mf;
	protected DefaultMutableTreeNode rootNode;
	protected DefaultTreeModel treeModel;
	Insets autoscrollInsets = new Insets(20, 20, 20, 20); // insets

	public ExerciseTree()
	{
	}

	public ExerciseTree(MainFrame mf,DefaultMutableTreeNode root)
	{
		// super(new GridLayout(1,0));
		this.mf = mf;
		this.rootNode = root;
		treeModel = new  DefaultTreeModel(rootNode);
		setModel(treeModel);
//		rootNode = new DefaultMutableTreeNode("Root Node");
//		treeModel = new DefaultTreeModel(rootNode);
		treeModel.addTreeModelListener(new MyTreeModelListener());
//		setDragEnabled(true);

		setEditable(false);
		getSelectionModel().setSelectionMode(
				TreeSelectionModel.SINGLE_TREE_SELECTION);
		setShowsRootHandles(true);
		setRootVisible(true); 
//		setShowsRootHandles(false);//to show the root icon

		new DefaultTreeTransferHandler(this, DnDConstants.ACTION_COPY_OR_MOVE);

	}
	
	public static DefaultMutableTreeNode makeDeepCopy(DefaultMutableTreeNode node) {
		DefaultMutableTreeNode copy = new DefaultMutableTreeNode(node.getUserObject());
		for (Enumeration e = node.children(); e.hasMoreElements();) {	
			copy.add(makeDeepCopy((DefaultMutableTreeNode)e.nextElement()));
		}
		return(copy);
	}

	public void autoscroll(Point cursorLocation)  {
		Insets insets = getAutoscrollInsets();
		Rectangle outer = getVisibleRect();
		Rectangle inner = new Rectangle(outer.x+insets.left, outer.y+insets.top, outer.width-(insets.left+insets.right), outer.height-(insets.top+insets.bottom));
		if (!inner.contains(cursorLocation))  {
			Rectangle scrollRect = new Rectangle(cursorLocation.x-insets.left, cursorLocation.y-insets.top,	insets.left+insets.right, insets.top+insets.bottom);
			scrollRectToVisible(scrollRect);
		}
	}
 
	public Insets getAutoscrollInsets()  {
		return (autoscrollInsets);
	}
	
	/** Remove all nodes except the root node. */
	public void clear()
	{
		rootNode.removeAllChildren();
		treeModel.reload();
	}

	/** Remove the currently selected node. */
	public void removeCurrentNode()
	{
		TreePath currentSelection = this.getSelectionPath();
		if (currentSelection != null)
		{
			DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection
					.getLastPathComponent());
			MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
			if (parent != null)
			{
				treeModel.removeNodeFromParent(currentNode);
				return;
			}
		}

	}

	/** Add child to the currently selected node. */
	public DefaultMutableTreeNode addObject(Object child)
	{
		DefaultMutableTreeNode parentNode = null;
		TreePath parentPath = this.getSelectionPath();

		if (parentPath == null)
		{
			parentNode = rootNode;
		} else
		{
			parentNode = (DefaultMutableTreeNode) (parentPath
					.getLastPathComponent());
		}

		return addObject(parentNode, child, true);
	}

	public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
			Object child)
	{
		return addObject(parent, child, false);
	}

	public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
			Object child, boolean shouldBeVisible)
	{
		DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child);

		if (parent == null)
		{
			parent = rootNode;
		}

		// It is key to invoke this on the TreeModel, and NOT
		// DefaultMutableTreeNode
		treeModel.insertNodeInto(childNode, parent, parent.getChildCount());

		// Make sure the user can see the lovely new node.
		if (shouldBeVisible)
		{
			this.scrollPathToVisible(new TreePath(childNode.getPath()));
		}
		return childNode;
	}

	class MyTreeModelListener implements TreeModelListener
	{
		public void treeNodesChanged(TreeModelEvent e)
		{
			DefaultMutableTreeNode node;
			node = (DefaultMutableTreeNode) (e.getTreePath()
					.getLastPathComponent());

			if (node.getParent() == node.getRoot()) // Current selected node is
													// exercise
			{
				// treeModel.nodeChanged()
				{

				}
			}

			if (node.isLeaf()
					&& (node.getParent().getParent() == node.getRoot())) // Current
																			// selected
																			// node
																			// is
																			// problem
			{

			}
			// Exercise exercise = (Exercise)node.getUserObject();
			/*
			 * If the event lists children, then the changed node is the child
			 * of the node we've already gotten. Otherwise, the changed node and
			 * the specified node are the same.
			 */

			int index = e.getChildIndices()[0];
			node = (DefaultMutableTreeNode) (node.getChildAt(index));

			System.out.println("The user has finished editing the node.");
			System.out.println("New value: " + node.getUserObject()
					+ "Node index: " + index);
			
			
		}

		public void treeNodesInserted(TreeModelEvent e)
		{
		}

		public void treeNodesRemoved(TreeModelEvent e)
		{
		}

		public void treeStructureChanged(TreeModelEvent e)
		{
		}
	}

	public void createTree()
	{
		// Create the exercise tree from the remote database

		try
		{
			// Create connection to the server
			PHPQuery phpQuery;
			// String url = "http://132.176.5.206/automata/test.php";
			String url = Config.REPOSITORY_SERVER;

			phpQuery = new PHPQuery(url);

			// set the parameter of query
			phpQuery.add("query_mode", "1");

			// Get the inputstream from the server

			DataInputStream dis = phpQuery.query();

			Element currentExerciseElement, currentProblemElement, tmpElement;

			String exerciseID, problemID;
			String exerciseName, problemName, problemGraph;

			NodeList currentNodeList, currentTxtList;
			NodeList exerciseList, problemList;

			Exercise currentExercise;
			Problem currentProblem;
			DefaultMutableTreeNode currentNode;

			// Construct the document from the inputstream
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(dis);

			// normalize text representation
			doc.getDocumentElement().normalize();

			// get a list of all the exercises
			exerciseList = doc.getElementsByTagName("exercise");

			for (int s = 0; s < exerciseList.getLength(); s++)
			{

				// get the current exercise
				currentExerciseElement = (Element) exerciseList.item(s);

				// get the exercise id
				currentNodeList = currentExerciseElement
						.getElementsByTagName("id");
				tmpElement = (Element) currentNodeList.item(0);

				currentTxtList = tmpElement.getChildNodes();

				exerciseID = ((Node) currentTxtList.item(0)).getNodeValue()
						.trim();

				// get the exercise name
				currentNodeList = currentExerciseElement
						.getElementsByTagName("name");
				tmpElement = (Element) currentNodeList.item(0);

				currentTxtList = tmpElement.getChildNodes();

				exerciseName = ((Node) currentTxtList.item(0)).getNodeValue()
						.trim();

				// create the new exercise
				// currentExercise = new Exercise(exerciseID, exerciseName);
				currentExercise = new Exercise(exerciseID, exerciseName, true);
				currentNode = addObject(null,
						new DefaultMutableTreeNode(currentExercise));

				// get the problems in each exercise

				problemList = currentExerciseElement
						.getElementsByTagName("problem");

				// get information for each problem
				for (int t = 0; t < problemList.getLength(); t++)
				{
					// get the current problem
					currentProblemElement = (Element) problemList.item(t);

					// get the problem id
					currentNodeList = currentProblemElement
							.getElementsByTagName("id");
					tmpElement = (Element) currentNodeList.item(0);

					currentTxtList = tmpElement.getChildNodes();

					problemID = ((Node) currentTxtList.item(0)).getNodeValue()
							.trim();

					// get the problem name
					currentNodeList = currentProblemElement
							.getElementsByTagName("name");
					tmpElement = (Element) currentNodeList.item(0);

					currentTxtList = tmpElement.getChildNodes();

					problemName = ((Node) currentTxtList.item(0))
							.getNodeValue().trim();

					// get the problem graph
					currentNodeList = currentProblemElement
							.getElementsByTagName("graph");
					tmpElement = (Element) currentNodeList.item(0);

					currentTxtList = tmpElement.getChildNodes();

					problemGraph = ((Node) currentTxtList.item(0)).getNodeValue().trim();

					if (!problemGraph.equals("empty"))
						problemGraph = new String(Base64.decode(problemGraph));

					// create the problem
					currentProblem = new Problem(problemID, problemName,
							"default problme describtion 1", problemGraph, 1);
					currentExercise.problems.add(currentProblem);
					addObject(currentNode, currentProblem);

				}

			}// end of for loop

		} catch (SAXParseException err)
		{
			System.out.println("** Parsing error" + ", line "
					+ err.getLineNumber() + ", uri " + err.getSystemId());
			System.out.println(" " + err.getMessage());

		} catch (SAXException e)
		{
			Exception x = e.getException();
			((x == null) ? e : x).printStackTrace();

		} catch (Throwable t)
		{
			t.printStackTrace();
		}
		

	}
}